package com.miyu.system.service.crawler.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.miyu.plugins.utils.Comutils;
import com.miyu.system.dao.rule.SysRuleDao;
import com.miyu.system.pojo.book.BookMain;
import com.miyu.system.pojo.crawler.BookPageVo;
import com.miyu.system.pojo.system.SysRule;
import com.miyu.system.service.crawler.BookService;
import com.miyu.system.service.rule.SysRuleService;
import com.miyu.system.utils.crawler.CrawlerUtils;
import com.miyu.system.utils.crawler.book.BookOperate;
import com.miyu.system.utils.crawler.book.BookPage;
import com.miyu.system.utils.crawler.book.BookSaveThread;
import com.miyu.system.utils.crawler.book.BookTaskThread;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.redis.cache.MicaRedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import us.codecraft.webmagic.Spider;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Book 服务实现
 *
 * @author longmiyu
 * &#064;date  2024/11/20
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class BookServiceImpl implements BookService {

    /**
     * Redis 缓存
     */
    private final MicaRedisCache redisCache;

    private final SysRuleService sysRuleService;

    /**
     * 书搜索
     *
     * @param params JSON 对象
     * @return {@link JSONArray }
     */
    @Override
    public JSONArray bookSearch(JSONObject params) {
        /*规则ID*/
        String ruleId = params.getString("ruleId");
        /* 搜索名称*/
        String name = params.getString("name");
        SysRule sysRule = sysRuleService.getSysRuleById(Integer.valueOf(ruleId));
        String  key = CrawlerUtils.REDIS_CACHE_BOOK+Comutils.getUUID();
        BookPageVo vo = new BookPageVo();
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
        vo.setRuleId(ruleId);
        vo.setKey(key);
        vo.setOperate(BookOperate.BOOK_SEARCH.getCode());
        if(rule.containsKey("method")&&rule.getString("method").equals(CrawlerUtils.METHOD_POST)){
            vo.setMethod(CrawlerUtils.METHOD_POST);
            if(rule.containsKey("searchKey")){
                //POST搜索参数
                JSONObject p = new JSONObject();
                p.put(rule.getString("searchKey"),name);
                vo.setParams(p);
            }
            if(rule.containsKey("paramsType")){
                if(rule.getString("paramsType").equals(CrawlerUtils.JSON)){
                    vo.setParamsType(CrawlerUtils.JSON);
                }else{
                    vo.setParamsType(CrawlerUtils.FORM);
                }
            }
            vo.setUrl(sysRule.getRootSearch());
        }else{
            String template = sysRule.getRootSearch();
            vo.setUrl(StrUtil.format(template, name));
            vo.setMethod(sysRule.getRootMethod());
        }

        redisCache.setEx(vo.getKey(),vo,vo.getTimeout(), TimeUnit.SECONDS);
        BookPage.bookSpider(vo);
        //获取当前key的缓存数据返回
        BookPageVo pv = redisCache.get(vo.getKey());
        return pv.getData().getJSONArray(BookOperate.BOOK_SEARCH.getCode());
    }

    /**
     * 书籍详情
     *
     * @param params JSON 对象
     * @return {@link JSONObject }
     */
    @Override
    public JSONObject bookDetail(JSONObject params) {
        /*规则ID*/
        Integer ruleId = params.getInteger("ruleId");
        String url = params.getString("url");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        String  key = CrawlerUtils.REDIS_CACHE_BOOK+Comutils.getUUID();
        BookPageVo vo = new BookPageVo();
        vo.setRuleId(String.valueOf(ruleId));
        vo.setUrl(url);
        vo.setKey(key);
        vo.setOperate(BookOperate.BOOK_DETAIL.getCode());
        redisCache.setEx(vo.getKey(),vo,vo.getTimeout(), TimeUnit.SECONDS);
        BookPage.bookSpider(vo);
        //获取当前key的缓存数据返回
        BookPageVo pv = redisCache.get(vo.getKey());
        return pv.getData().getJSONArray(BookOperate.BOOK_DETAIL.getCode()).getJSONObject(0);

    }

    /**
     * 书籍章节
     *
     * @param params JSON 对象
     * @return {@link JSONArray }
     */
    @Override
    public JSONArray bookChapter(JSONObject params) {
        Integer ruleId = params.getInteger("ruleId");
        String url = params.getString("url");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        String  key = CrawlerUtils.REDIS_CACHE_BOOK+Comutils.getUUID();
        BookPageVo vo = new BookPageVo();
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
        vo.setRuleId(String.valueOf(ruleId));
        vo.setUrl(url);
        vo.setKey(key);
        vo.setOperate(BookOperate.BOOK_CHAPTER.getCode());
        redisCache.setEx(vo.getKey(),vo,vo.getTimeout(), TimeUnit.SECONDS);
        BookPage.bookSpider(vo);
        //获取当前key的缓存数据返回
        BookPageVo pv = redisCache.get(vo.getKey());
        return pv.getData().getJSONArray(BookOperate.BOOK_CHAPTER.getCode());
    }

    /**`
     * 书籍内容
     *
     * @param params JSON 对象
     * @return {@link JSONObject }
     */
    @Override
    public JSONObject bookContent(JSONObject params) {
        Integer ruleId = params.getInteger("ruleId");
        String url = params.getString("url");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        String  key = CrawlerUtils.REDIS_CACHE_BOOK+Comutils.getUUID();
        BookPageVo vo = new BookPageVo();
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
        vo.setRuleId(String.valueOf(ruleId));
        vo.setUrl(url);
        vo.setKey(key);
        vo.setOperate(BookOperate.BOOK_READER.getCode());
        redisCache.setEx(vo.getKey(),vo,vo.getTimeout(), TimeUnit.SECONDS);

//        ExecutorService exec = Executors.newFixedThreadPool(CrawlerUtils.BOOK_CRAWLER_MAX_THREAD);// 线程数
//        exec.submit(new BookTaskThread(vo));
//
        BookPage.bookSpider(vo);
        //获取当前key的缓存数据返回
        BookPageVo pv = redisCache.get(vo.getKey());
        return pv.getData().getJSONArray(BookOperate.BOOK_READER.getCode()).getJSONObject(0);
    }

    /**
     * 实例化 收集书
     * url地址 根据明细页  跳转章节 获取连接 再获取阅读页数据
     * @param params 本页面
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject collectBook(JSONObject params) {



        //根据规则取出url
        Integer ruleId = params.getInteger("ruleId");
        for(int i=10000;i<10001;i++){

            String template = "https://www.22is.com/book/{}.html";
            String url = StrUtil.format(template, i);

//            String url = params.getString("url");
            SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
            String  key = CrawlerUtils.REDIS_CACHE_BOOK_COLLECT+Comutils.getUUID();
            BookPageVo vo = new BookPageVo();
            JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
//            vo.setSysRule(sysRule);
            vo.setRuleId(String.valueOf(ruleId));
            vo.setUrl(url);
            vo.setKey(key);
            vo.setOperate(BookOperate.COLLECT.getCode());
            //采取主动删除缓存策略
            redisCache.set(vo.getKey(),vo);
            /* 唤醒多线程解析收集数据*/
            ExecutorService exec = Executors.newFixedThreadPool(CrawlerUtils.BOOK_CRAWLER_MAX_THREAD);// 线程数
            exec.submit(new BookTaskThread(vo));



        }





//        BookPage.bookSpider(vo);
        //获取当前key的缓存数据返回
//        BookPageVo pv = redisCache.get(vo.getKey());
        /*异步操作 保存数据*/
        JSONObject result = new JSONObject();
        result.put("code","1");
        result.put("data","数据采集中。。。");
        return result;

    }

    /**
     * 保存书籍
     * 收集后数据 手动执行保存数据
     *
     * @param params 参数
     * @return {@link JSONObject }
     */
    @Override
    public JSONObject saveBook(JSONObject params) {
        JSONObject p = new JSONObject();
        p.put("code","1");
        p.put("msg","进入保存数据线程");
        ExecutorService exec = Executors.newFixedThreadPool(1);// 线程数
        for (int i = 0; i < 1; i++) {
            exec.submit(new BookSaveThread(p));
        }



//        long i=1;
//        Set<String> scan = redisCache.scan(CrawlerUtils.REDIS_CACHE_BOOK_COLLECT+"*");
//
//        if(!scan.isEmpty()){
//            for (String key : scan) {
//                BookPageVo vp =  redisCache.get(key);
//
//                //解析保存数据
//                List<String> sqlList =  bookSaveJx(vp);
//                if(sqlList.size()>0){
//                    sysRuleDao.doExecuteBatch(sqlList);
//                }
//                System.out.println(sqlList.size());
//            }
//         //   移除所有key
//            redisCache.del(scan);
//        }


        JSONObject result = new JSONObject();
        result.put("code","1");
        result.put("data","执行保存中。。。。。。");
        return result;
    }

    /**
     * 获取参数 执行操作
     * 图书操作爬虫
     *
     * @param params 参数
     * @return {@link JSONObject }
     */
    @Override
    public JSONObject execSpider(JSONObject params) {



        JSONObject result = new JSONObject();
        Integer ruleId = params.getInteger("ruleId");

//            String url = params.getString("url");
        SysRule sysRule = sysRuleService.getSysRuleById(ruleId);
        String  key = CrawlerUtils.REDIS_CACHE_BOOK_COLLECT+Comutils.getUUID();
        BookPageVo vo = new BookPageVo();
        JSONObject rule = JSONObject.parseObject(sysRule.getRuleSet());
//        vo.setSysRule(sysRule);
        vo.setRuleId(String.valueOf(ruleId));
        vo.setUrl("https://www.22is.com/book/10000.html");
        vo.setKey(key);
        vo.setOperate(BookOperate.COLLECT.getCode());
//        vo.setRule(rule.getJSONObject(BookOperate.BOOK_DETAIL.getCode()));

        BookPage.bookSpider(vo);


            Spider spider = Spider.create(new BookPage());
//        spider.setScheduler(new RedisScheduler("127.0.0.1:6379"));


            // 启动后可以获取URL队列的大小
            spider.start();
        log.info("存在线程数：{}",spider.getThreadAlive());
        log.info("状态：{}",spider.getStatus());
        log.info("url：{}",spider.getPageCount());
        log.info("sc：{}",spider.getScheduler());

            result.put("code","1");
            result.put("msg","参数");
        return result;
    }

    private List<String> bookSaveJx(BookPageVo pv) {
        String[] table = CrawlerUtils.BOOK_CHAPTER;
        Random rd=new Random();
        String ta = pv.getRuleId()+"_"+table[rd.nextInt(table.length)];
        String mainTable = "book_main_"+pv.getRuleId();
        String chapterTable = "book_chapter_"+ta;

        List<String> sqlList = new ArrayList<String>();
        JSONArray jsonArray = pv.getData().getJSONArray(BookOperate.BOOK_DETAIL.getCode());
        if(jsonArray==null||jsonArray.isEmpty()){
            return sqlList;
        }
        JSONObject bookDetail = jsonArray.getJSONObject(0);
        JSONArray bookChapter =  pv.getData().getJSONArray(BookOperate.BOOK_CHAPTER.getCode());
        /** 数据转换*/
        BookMain bookMain = JSONObject.parseObject(bookDetail.toJSONString(), BookMain.class);

        bookMain.setRuleId(pv.getRuleId());///规则主键
        bookMain.setType("0");//类型0 text 1 其他
        bookMain.setBookId(Comutils.getId(CrawlerUtils.TABLE_BOOK_MAIN));//书Id
        StringBuffer main = new StringBuffer();
        main.append("insert into ").append(mainTable).append("(book_id,rule_id,book_url,toc_url,name,author,kind,cover_url,intro,type,latest_chapter_title,");
        main.append(" latest_chapter_time,last_check_count,total_chapter_num)");
        main.append("values(");
        main.append("'").append(isNullToStr(bookMain.getBookId()) ).append("',");
        main.append("'").append(isNullToStr(bookMain.getRuleId())).append("',");
        main.append("'").append(isNullToStr(bookMain.getBookUrl())).append("',");
        main.append("'").append(isNullToStr(bookMain.getTocUrl())).append("',");
        main.append("'").append(isNullToStr(bookMain.getName())).append("',");
        main.append("'").append(isNullToStr(bookMain.getAuthor())).append("',");
        main.append("'").append(isNullToStr(bookMain.getKind())).append("',");
        main.append("'").append(isNullToStr(bookMain.getCoverUrl())).append("',");
        main.append("'").append(isNullToStr(bookMain.getIntro())).append("',");
        main.append("'").append(isNullToStr(bookMain.getType())).append("',");
        main.append("'").append(isNullToStr(bookMain.getLatestChapterTitle())).append("',");
        main.append("'").append(isNullToStr(bookMain.getLastCheckTime())).append("',");
        main.append("'").append(isNullToStr(bookMain.getLastCheckCount())).append("',");
        main.append("'").append(isNullToStr(bookMain.getTotalChapterNum())).append("')");
        sqlList.add(main.toString());
        if(!(bookChapter==null||bookChapter.isEmpty())){
            for (int i = 0; i < bookChapter.size(); i++) {
                JSONObject chapter = bookChapter.getJSONObject(i);
                StringBuffer sb = new StringBuffer();
                sb.append("insert into ").append("");
                sb.append(chapterTable);
                sb.append("(chapter_id,book_id,url,title,num)");
                sb.append("values(");
                sb.append("'").append(Comutils.getId(CrawlerUtils.TABLE_BOOK_CHAPTER)).append("',");
                sb.append("'").append(isNullToStr(bookMain.getBookId())).append("',");
                sb.append("'").append(isNullToStr(chapter.getString("url"))).append("',");
                sb.append("'").append(isNullToStr(chapter.getString("title"))).append("',");
                sb.append("'").append(isNullToStr(chapter.getString("num"))).append("')");
                sqlList.add(sb.toString());
            }
        }
        return sqlList;
    }

    private String isNullToStr(Object obj) {
        String str="";
        if("null".equals(obj)||null==obj||StrUtil.isEmpty(String.valueOf(obj))){
            str="";
        }else{
            return String.valueOf(obj);
        }
        return str;
    }

    /**
     * 书籍下载
     * 3种下载 单章节下载 ；单章节合并 下载；链接下载
     *
     * @param params 参数
     * @return {@link JSONObject }
     */
    @Override
    public JSONObject bookDownLoad(JSONObject params) {
        return null;
    }




}
